//一个工具库，封装了使用three.js的操作

import * as THREE from './three/build/three.module.js'

import {OrbitControls} from './three/jsm/controls/OrbitControls.js'
import {GLTFLoader} from './three/jsm/loaders/GLTFLoader.js'

let scene
let camera
let renderer
let controls
let model, modelHasLoad, ground
let ambientLight, sunLight

const clock = new THREE.Clock()
let animations, mixer

const LIGHT_RANGE = 30 //光照范围，无需更改
const PUSHER_RANGE = 34 //推杆推出的长度，单位cm
const PUSHER_SPEED = 54 //推杆线速度，单位cm/s
const PUSHER_DURATION = PUSHER_RANGE / PUSHER_SPEED
const BELT_SHORT_RANGE = 2 //上货端传送带长度，单位m
const BELT_LONG_RANGE = 3 //分拣端传送带长度，单位m

//场景
function initScene(){
    scene = new THREE.Scene()
}

//相机
function initCamera() {
    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
    camera.position.set(-1, 15.5, 20.5)
    camera.lookAt(0, 10, 0)
}

//渲染器
function initRenderer() {
    renderer = new THREE.WebGLRenderer({antialias: true}) //抗锯齿
    renderer.setSize(window.innerWidth, window.innerHeight)
    renderer.setClearColor(0x333333) //背景色
    renderer.shadowMap.enabled = true //开启阴影，加上阴影渲染
}

//模型
function initModel(modelPath) {
    //GLB模型
    let loader = new GLTFLoader()
    loader.load(modelPath, (glb) => {
        model = glb.scene
        model.traverse((child) => {
            child.castShadow = true
            child.receiveShadow = true
        })
        modelHasLoad = true

        scene.add(glb.scene)

        //模型动画
        mixer = new THREE.AnimationMixer(model)

        animations = glb.animations
        for (let i = 0; i < 6; i ++){
            let action = mixer.clipAction(animations[i])
            action.setLoop(THREE.LoopPingPong)
            action.timeScale = PUSHER_SPEED / PUSHER_RANGE
        }
        mixer.clipAction(animations[6]).play()
        mixer.clipAction(animations[6]).paused = true
        mixer.clipAction(animations[7]).play()
        mixer.clipAction(animations[7]).paused = true
    })

    //场景
    let planeGeometry = new THREE.PlaneGeometry(4000, 4000)
    let planeMaterial = new THREE.MeshLambertMaterial({color: 0x305075})
    ground = new THREE.Mesh(planeGeometry, planeMaterial)
    ground.rotation.x = - Math.PI / 2
    ground.receiveShadow = true
    scene.add(ground)
}

//添加光照
function initLight() {
    //环境光
    ambientLight = new THREE.AmbientLight(0x555555)
    scene.add(ambientLight)

    //平行光
    sunLight = new THREE.DirectionalLight(0xffffee)
    sunLight.position.set(-50, 45, 30)
    sunLight.castShadow = true //开启阴影投射

    //设置阴影属性
    sunLight.shadow.camera.far = 100
    sunLight.shadow.camera.fov = 100
    sunLight.shadow.camera.near = 0.01
    sunLight.shadow.camera.left = - LIGHT_RANGE
    sunLight.shadow.camera.right = LIGHT_RANGE
    sunLight.shadow.camera.top = LIGHT_RANGE
    sunLight.shadow.camera.bottom = - LIGHT_RANGE
    sunLight.shadow.normalBias = 0.1
    sunLight.shadow.mapSize.width = 1024
    sunLight.shadow.mapSize.height = 1024
    scene.add(sunLight)
}

//控制器
function initControls() {
    controls = new OrbitControls(camera, renderer.domElement)
    controls.maxPolarAngle = Math.PI * 0.5 - 0.01 //限制转动角度
    controls.maxDistance = 100 //限制镜头最远距离
    controls.minDistance = 5 //限制镜头最近距离
}

//窗口大小改变时触发
function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()

    renderer.setSize(window.innerWidth, window.innerHeight)
}

function animate() {
    requestAnimationFrame(animate)
    render()
}

function render() {
    let delta = clock.getDelta()

    if (modelHasLoad) {
        //播放动画
        mixer.update(delta)
        renderer.render(scene, camera)
    }
}

function init(modelPath) {
    initScene()
    initCamera()
    initRenderer()
    initModel(modelPath)
    initLight()
    initControls()

    document.body.appendChild(renderer.domElement)
    window.onresize = onWindowResize

    animate()
}

//以下函数为工具类函数
function push(num, holdTime) {
    let action = mixer.clipAction(animations[num - 1])
    action.play()

    if (holdTime < 0.2){
        holdTime = 0.2
    }

    setTimeout(() => {
        action.paused = true

        setTimeout(() => {
            action.paused = false

            setTimeout(() => {
                action.stop()
            }, PUSHER_DURATION * 1000)
        }, holdTime * 1000)
    }, PUSHER_DURATION * 1000)
}

function rollShort(speed) {
    let action = mixer.clipAction(animations[6])
    action.timeScale = 0.5 / (BELT_SHORT_RANGE / (speed / 60))
    action.paused = false
}
function rollLong(speed) {
    let action = mixer.clipAction(animations[7])
    action.timeScale = (0.5 / (BELT_LONG_RANGE / (speed / 60)))
    action.paused = false
}

function stopShort() {
    let action = mixer.clipAction(animations[6])
    action.paused = true
}
function stopLong() {
    let action = mixer.clipAction(animations[7])
    action.paused = true
}

export {init, push, rollShort, rollLong, stopShort, stopLong}